return n;
}
-#define pixels 8192*2
+#define test_pixels 512
static double *
test_create (void)
srandom (20050728);
- test = babl_malloc (sizeof (double) * pixels * 4);
+ test = babl_malloc (sizeof (double) * test_pixels * 4);
- for (i = 0; i < pixels * 4; i++)
+ for (i = 0; i < test_pixels * 4; i++)
test [i] = (double) random () / RAND_MAX;
-
return test;
}
+long
+babl_conversion_cost (BablConversion *conversion)
+{
+ if (!conversion)
+ return 100000000.0;
+ if (conversion->error==-1.0)
+ babl_conversion_error (conversion);
+ return conversion->cost;
+}
+
double
babl_conversion_error (BablConversion *conversion)
{
Babl *fmt_source;
Babl *fmt_destination;
- Babl *fmt_rgba_double;
+ Babl *fmt_rgba_double = fmt_rgba_double = babl_format_new (
+ babl_model ("RGBA"),
+ babl_type ("double"),
+ babl_component ("R"),
+ babl_component ("G"),
+ babl_component ("B"),
+ babl_component ("A"),
+ NULL);
double error = 0.0;
unsigned int ticks_start = 0;
void *ref_destination;
double *ref_destination_rgba_double;
+ Babl *fish_rgba_to_source;
+ Babl *fish_reference;
+ Babl *fish_destination_to_rgba;
if (!conversion)
return 0.0;
fmt_source = BABL(conversion->source);
fmt_destination = BABL(conversion->destination);
+ fish_rgba_to_source = babl_fish_reference (fmt_rgba_double, fmt_source);
+ fish_reference = babl_fish_reference (fmt_source, fmt_destination);
+ fish_destination_to_rgba = babl_fish_reference (fmt_destination, fmt_rgba_double);
+
if (fmt_source == fmt_destination)
{
conversion->error = 0.0;
return 0.0;
}
- if (!(fmt_source->instance.id != BABL_RGBA &&
+ if (!(fmt_source->instance.id != BABL_RGBA &&
fmt_destination->instance.id != BABL_RGBA &&
fmt_source->instance.id != BABL_DOUBLE &&
fmt_destination->instance.id != BABL_DOUBLE &&
test=test_create ();
- fmt_rgba_double = babl_format_new (
- babl_model ("RGBA"),
- babl_type ("double"),
- babl_component ("R"),
- babl_component ("G"),
- babl_component ("B"),
- babl_component ("A"),
- NULL);
-
- source = babl_calloc (pixels, fmt_source->format.bytes_per_pixel);
- destination = babl_calloc (pixels, fmt_destination->format.bytes_per_pixel);
- ref_destination = babl_calloc (pixels, fmt_destination->format.bytes_per_pixel);
- destination_rgba_double = babl_calloc (pixels, fmt_rgba_double->format.bytes_per_pixel);
- ref_destination_rgba_double = babl_calloc (pixels, fmt_rgba_double->format.bytes_per_pixel);
+ source = babl_calloc (test_pixels, fmt_source->format.bytes_per_pixel);
+ destination = babl_calloc (test_pixels, fmt_destination->format.bytes_per_pixel);
+ ref_destination = babl_calloc (test_pixels, fmt_destination->format.bytes_per_pixel);
+ destination_rgba_double = babl_calloc (test_pixels, fmt_rgba_double->format.bytes_per_pixel);
+ ref_destination_rgba_double = babl_calloc (test_pixels, fmt_rgba_double->format.bytes_per_pixel);
- babl_process (babl_fish_reference (fmt_rgba_double, fmt_source),
- test, source, pixels);
+ babl_process (fish_rgba_to_source,
+ test, source, test_pixels);
ticks_start = babl_ticks ();
babl_process (babl_fish_simple (conversion),
- source, destination, pixels);
+ source, destination, test_pixels);
ticks_end = babl_ticks ();
- babl_process (babl_fish_reference (fmt_source, fmt_destination),
- source, ref_destination, pixels);
+ babl_process (fish_reference,
+ source, ref_destination, test_pixels);
- babl_process (babl_fish_reference (fmt_destination, fmt_rgba_double),
- ref_destination, ref_destination_rgba_double, pixels);
- babl_process (babl_fish_reference (fmt_destination, fmt_rgba_double),
- destination, destination_rgba_double, pixels);
+ babl_process (fish_destination_to_rgba,
+ ref_destination, ref_destination_rgba_double, test_pixels);
+ babl_process (fish_destination_to_rgba,
+ destination, destination_rgba_double, test_pixels);
- {
- int i;
+ error = babl_rel_avg_error (destination_rgba_double,
+ ref_destination_rgba_double,
+ test_pixels*4);
+
+ fish_rgba_to_source->fish.processings--;
+ fish_reference->fish.processings--;
+ fish_destination_to_rgba->fish.processings-=2;
+
+ fish_rgba_to_source->fish.pixels -= test_pixels;
+ fish_reference->fish.pixels -= test_pixels;
+ fish_destination_to_rgba->fish.pixels -= 2 * test_pixels;
- for (i=0;i<pixels;i++)
- {
- int j;
- for (j=0;j<4;j++)
- error += fabs (destination_rgba_double[i*4+j] -
- ref_destination_rgba_double[i*4+j]);
- }
- error /= pixels;
- error *= 100;
- }
babl_free (source);
babl_free (destination);
return error;
}
-
BABL_CLASS_TEMPLATE (conversion)
* Boston, MA 02111-1307, USA.
*/
+#include <math.h>
#include "babl-internal.h"
-#define BABL_LEGAL_ERROR 0.000001
+static double
+chain_error (Babl *fmt_source,
+ Babl *fmt_destination,
+ BablConversion **chain,
+ int conversions);
+
+//#define BABL_LEGAL_ERROR 0.000001
+//#define BABL_LEGAL_ERROR 0.01
+
+static double legal_error (void)
+{
+ double error=0.00000001;
+ const char *env;
+
+ env=getenv ("BABL_ERROR");
+ if (env)
+ error = atof (env);
+ else if (error<=0.0)
+ error = 0.0;
+ return error;
+}
+
+static int max_path_length (void)
+{
+ int max_length=3;
+ const char *env;
+
+ env=getenv ("BABL_PATH_LENGTH");
+ if (env)
+ max_length = atoi (env);
+ if (max_length>BABL_HARD_MAX_PATH_LENGTH)
+ max_length=BABL_HARD_MAX_PATH_LENGTH;
+ else if (max_length<=0)
+ max_length = 1;
+ return max_length;
+}
typedef struct BablChainContext {
Babl *from;
double *best_cost;
double *best_loss;
+ double *best_error;
- Babl **chain;
+ BablConversion **chain;
int *conversions;
- Babl **temp_chain;
+ BablConversion **temp_chain;
int temp_conversions;
int max_conversions;
} BablChainContext;
-static int
-format_has_alpha (Babl *babl)
-{
- int i;
- for (i=0; i<babl->format.components; i++)
- if (babl->format.component[i]->instance.id == BABL_ALPHA)
- return 1;
- return 0;
-}
-
-static int
-format_analytic_loss (Babl *source,
- Babl *destination)
-{
- int loss = 0;
-
- if (source->format.components <
- destination->format.components)
- {
- loss |= 8;
- }
-
- if ( format_has_alpha (source) &&
- !format_has_alpha (destination))
- {
- loss |= 4;
- }
-
- if ( BABL(source->format.type[0])->type.bits >
- BABL(destination->format.type[0])->type.bits)
- {
- loss |= 2;
- }
-
- if ( source->format.bytes_per_pixel >
- destination->format.bytes_per_pixel)
- {
- loss |= 1;
- }
-
-
-
-
- return loss;
-}
-
-
static int
chain_gen_each (Babl *babl,
void *userdata);
static int
-get_conversion_chain (Babl *from,
- Babl *to,
-
- double *best_cost,
- double *best_loss,
- Babl **chain,
- int *conversions,
-
- Babl **temp_chain,
- int temp_conversions,
-
- int max_conversions)
+get_conversion_chain (Babl *from,
+ Babl *to,
+ double *best_cost,
+ double *best_loss,
+ double *best_error,
+ BablConversion **chain,
+ int *conversions,
+ BablConversion **temp_chain,
+ int temp_conversions,
+ int max_conversions)
{
BablChainContext context;
*conversions = 0;
*best_cost = 200000.0;
*best_loss = 200000.0;
+ *best_error = 200000.0;
chain[0] = NULL;
temp_chain[0] = NULL;
context.best_cost = best_cost;
context.best_loss = best_loss;
+ context.best_error = best_error;
context.chain = chain;
context.conversions = conversions;
else
{
if (BABL(temp_chain[temp_conversions-1]) &&
- BABL(temp_chain[temp_conversions-1]->conversion.destination)->
+ BABL(temp_chain[temp_conversions-1]->destination)->
format.from)
babl_list_each (
(void **)
- BABL(temp_chain[temp_conversions-1]->conversion.destination)->
+ BABL(temp_chain[temp_conversions-1]->destination)->
format.from,
chain_gen_each,
&context);
return 0;
}
+static int
+chain_contains_fmt (BablConversion **chain,
+ int conversions,
+ Babl *fmt)
+{
+ int i;
+ for (i=0;i<conversions;i++)
+ if (BABL(chain[i]->destination)==fmt ||
+ BABL(chain[i]->source)==fmt)
+ {
+ return 1;
+ }
+ return 0;
+}
+
static int
chain_gen_each (Babl *babl,
void *userdata)
BablChainContext *c = userdata;
/* fill in the conversion for the chain index we are at */
- c->temp_chain[c->temp_conversions] = babl;
+ c->temp_chain[c->temp_conversions] = (BablConversion*)babl;
{
- if (BABL(babl->conversion.destination) == c->to)
+ if ((BABL(babl->conversion.destination) == c->to) )
{
/* a candidate path has been found */
- double temp_cost = 0.0;
- double temp_loss = 0.0;
- double error = 1.0;
- int analytic_loss = 0;
+ double temp_cost = 0.0;
+ double temp_error = 1.0;
int i;
for (i=0; i < c->temp_conversions+1; i++)
{
- error *= (1.0+c->temp_chain[i]->conversion.error);
- temp_cost += c->temp_chain[i]->conversion.cost;
- analytic_loss |= format_analytic_loss (
- BABL(c->temp_chain[i]->conversion.source),
- BABL(c->temp_chain[i]->conversion.destination));
+ temp_error *= (1.0+babl_conversion_error (c->temp_chain[i]));
+ temp_cost += babl_conversion_cost (c->temp_chain[i]);
}
- temp_loss = analytic_loss;
- if (error <= (1.0 + BABL_LEGAL_ERROR) /* we're legal */ &&
- (temp_loss >= format_analytic_loss (c->from, c->to)) &&
-
-
- /* better than the existing best candidate */
- ( temp_loss < *c->best_loss ||
- (temp_loss == *c->best_loss &&
- temp_cost < *c->best_cost)))
+ if (temp_cost < *c->best_cost &&
+ temp_error - 1.0 <= legal_error() && /* this check before the next; which does a more accurate
+ measurement of the error */
+ (temp_error=chain_error (c->from, c->to, c->temp_chain, c->temp_conversions+1)) <= legal_error()
+ )
{
int i;
*c->best_cost = temp_cost;
- *c->best_loss = temp_loss;
+ *c->best_error = temp_error;
*c->conversions = c->temp_conversions + 1;
/* copy from temp chain to best chain */
- for (i = 0.0; i < *c->conversions; i++)
+ for (i = 0; i < *c->conversions; i++)
c->chain[i] = c->temp_chain[i];
}
}
- else
+ else if (babl->conversion.source != babl->conversion.destination &&
+ !chain_contains_fmt (c->temp_chain,
+ c->temp_conversions,
+ BABL(babl->conversion.destination)))
{
/* try to add another conversion level in chain,.. */
get_conversion_chain (c->from, /* irrelevant when recalled */
c->best_cost,
c->best_loss,
+ c->best_error,
c->chain,
c->conversions,
{
Babl *babl = NULL;
char *name = create_name (source, destination, 1);
- Babl *temp_chain[BABL_MAX_PATH_LENGTH];
+ BablConversion *temp_chain[BABL_HARD_MAX_PATH_LENGTH];
babl_assert (BABL_IS_BABL (source));
babl_assert (BABL_IS_BABL (destination));
babl->fish.processings = 0;
babl->fish.pixels = 0;
+ babl->fish.error = 200000;
babl->fish_path.cost = 200000;
babl->fish_path.loss = 200000;
destination,
&babl->fish_path.cost,
&babl->fish_path.loss,
- (Babl**)(babl->fish_path.conversion),
+ &babl->fish.error,
+ (BablConversion**)(babl->fish_path.conversion),
&babl->fish_path.conversions,
temp_chain,
0,
- BABL_MAX_PATH_LENGTH);
+ max_path_length ());
+
if (babl->fish_path.conversions==0)
{
babl_free (babl);
for (i=0; i<conversions; i++)
{
- if (i==0 && conversions == i+1)
+ if (i==0 && conversions == 1)
{
babl_conversion_process ( BABL(chain[i]),
source, destination, n);
babl_conversion_process ( BABL(chain[i]),
source, bufA, n);
}
- else if (i % 2 == 1)
+ else if (i % 2 == 0)
{
if (i + 1 == conversions)
{
babl_conversion_process ( BABL(chain[i]),
- bufA, destination, n);
+ bufB, destination, n);
}
else
{
babl_conversion_process ( BABL(chain[i]),
- bufA, bufB, n);
+ bufB, bufA, n);
}
}
- else if (i % 2 == 0)
+ else if (i % 2 == 1)
{
if (i + 1 == conversions)
{
babl_conversion_process ( BABL(chain[i]),
- bufB, destination, n);
+ bufA, destination, n);
}
else
{
babl_conversion_process ( BABL(chain[i]),
- bufB, bufA, n);
+ bufA, bufB, n);
}
}
- i ++;
}
if (bufA)
babl_free (bufA);
void *destination,
long n)
{
- /*
- int i;
- */
-
babl_assert (source);
babl_assert (destination);
-/*
- babl_log ("path processing from %s to %s",
- BABL(babl->fish.source)->instance.name,
- BABL(babl->fish.destination)->instance.name);
-
- for (i=0; i< babl->fish_path.conversions; i++)
- babl_log ("\t%s\n",
- BABL(babl->fish_path.conversion[i])->instance.name);
-*/
return chain_process (babl->fish_path.conversion,
babl->fish_path.conversions,
n);
}
+
+#define test_pixels 128
+
+static double *
+test_create (void)
+{
+ double *test;
+ int i;
+
+ srandom (20050728);
+
+ test = babl_malloc (sizeof (double) * test_pixels * 4);
+
+ for (i = 0; i < test_pixels * 4; i++)
+ test [i] = (double) random () / RAND_MAX;
+
+ return test;
+}
+
+static double
+chain_error (Babl *fmt_source,
+ Babl *fmt_destination,
+ BablConversion **chain,
+ int conversions)
+{
+ Babl *fmt_rgba_double = babl_format_new (
+ babl_model ("RGBA"),
+ babl_type ("double"),
+ babl_component ("R"),
+ babl_component ("G"),
+ babl_component ("B"),
+ babl_component ("A"),
+ NULL);
+
+ double error = 0.0;
+
+ double *test;
+ void *source;
+ void *destination;
+ double *destination_rgba_double;
+ void *ref_destination;
+ double *ref_destination_rgba_double;
+
+ Babl *fish_rgba_to_source = babl_fish_reference (fmt_rgba_double, fmt_source);
+ Babl *fish_reference = babl_fish_reference (fmt_source, fmt_destination);
+ Babl *fish_destination_to_rgba = babl_fish_reference (fmt_destination, fmt_rgba_double);
+
+ test=test_create ();
+
+
+ source = babl_calloc (test_pixels, fmt_source->format.bytes_per_pixel);
+ destination = babl_calloc (test_pixels, fmt_destination->format.bytes_per_pixel);
+ ref_destination = babl_calloc (test_pixels, fmt_destination->format.bytes_per_pixel);
+ destination_rgba_double = babl_calloc (test_pixels, fmt_rgba_double->format.bytes_per_pixel);
+ ref_destination_rgba_double = babl_calloc (test_pixels, fmt_rgba_double->format.bytes_per_pixel);
+
+ /* create sourcebuffer from testbuffer in the correct format */
+ babl_process (fish_rgba_to_source,
+ test, source, test_pixels);
+
+ /* calculate the reference buffer of how it should be */
+ babl_process (fish_reference,
+ source, ref_destination, test_pixels);
+
+ /* calculate this chains view of what the result should be */
+ chain_process (chain, conversions, source, destination, test_pixels);
+
+ /* transform the reference and the actual destination buffers to RGBA
+ * for comparison with each other
+ */
+ babl_process (fish_destination_to_rgba,
+ ref_destination, ref_destination_rgba_double, test_pixels);
+ babl_process (fish_destination_to_rgba,
+ destination, destination_rgba_double, test_pixels);
+
+ error = babl_rel_avg_error (destination_rgba_double,
+ ref_destination_rgba_double,
+ test_pixels*4);
+
+ fish_rgba_to_source->fish.processings--;
+ fish_reference->fish.processings--;
+ fish_destination_to_rgba->fish.processings-=2;
+
+ fish_rgba_to_source->fish.pixels -= test_pixels;
+ fish_reference->fish.pixels -= test_pixels;
+ fish_destination_to_rgba->fish.pixels -= 2 * test_pixels;
+
+ babl_free (source);
+ babl_free (destination);
+ babl_free (destination_rgba_double);
+ babl_free (ref_destination);
+ babl_free (ref_destination_rgba_double);
+ babl_free (test);
+
+ return error;
+}
#define TOLERANCE 0.001
-#define pixels 512
+#define test_pixels 512
static double *
test_create (void)
srandom (20050728);
- test = babl_malloc (sizeof (double) * pixels * 4);
+ test = babl_malloc (sizeof (double) * test_pixels * 4);
- for (i = 0; i < pixels * 4; i++)
+ for (i = 0; i < test_pixels * 4; i++)
test [i] = ((double) random () / RAND_MAX ) * 1.4 - 0.2;
return test;
fish_to = babl_fish_reference (ref_fmt, fmt);
fish_from = babl_fish_reference (fmt, ref_fmt);
- original = babl_calloc (1,64/8 * babl->model.components * pixels);
- clipped = babl_calloc (1,64/8 * 4 * pixels);
- destination = babl_calloc (1,64/8 * babl->model.components * pixels);
- transformed = babl_calloc (1,64/8 * 4 * pixels);
+ original = babl_calloc (1,64/8 * babl->model.components * test_pixels);
+ clipped = babl_calloc (1,64/8 * 4 * test_pixels);
+ destination = babl_calloc (1,64/8 * babl->model.components * test_pixels);
+ transformed = babl_calloc (1,64/8 * 4 * test_pixels);
- babl_process (fish_to, test, original, pixels);
- babl_process (fish_from, original, clipped, pixels);
- babl_process (fish_to, clipped, destination, pixels);
- babl_process (fish_from, destination, transformed, pixels);
+ babl_process (fish_to, test, original, test_pixels);
+ babl_process (fish_from, original, clipped, test_pixels);
+ babl_process (fish_to, clipped, destination, test_pixels);
+ babl_process (fish_from, destination, transformed, test_pixels);
+
+ fish_to->fish.processings-=2;
+ fish_from->fish.processings-=2;
+ fish_to->fish.pixels-=test_pixels*2;
+ fish_from->fish.pixels -= test_pixels*2;
{
int i;
int log=0;
- for (i=0;i<pixels;i++)
+ for (i=0;i<test_pixels;i++)
{
int j;
for (j=0;j<4;j++)